#ifndef CLUSNET_NET_TCPSERVER_H
#define CLUSNET_NET_TCPSERVER_H

#include <memory>
#include <unordered_set>
#include <boost/asio.hpp>
#include <vector>
#include <string>
#include <clusnet/base/Thread.h>
#include "TcpAcceptor.h"
#include "Callbacks.h"

namespace clusnet
{
namespace net
{

class TcpServer final
{
        using Work = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
    public:
        TcpServer(const char* host, unsigned short port);
        TcpServer(unsigned short port, const boost::asio::ip::tcp::resolver::protocol_type& proto = boost::asio::ip::tcp::v4());
        TcpServer(const boost::asio::ip::tcp::endpoint& endpoint);
        ~TcpServer();
        TcpServer(const TcpServer&) = delete;
        TcpServer& operator= (const TcpServer&) = delete;

    public:
        void start(size_t numThreads = 1, size_t ioNum = 0);
        void stop();
        void setNewConnectionCallback(const TcpNewConnectionCallback& cb) { newConnCallback_ = cb; }
        void setWriteCompleteCallback(const TcpWriteCompleteCallback& cb) { writeCallback_ = cb; }
        void setMessageCallback(const TcpMessageCallback& cb) { messageCallback_ = cb; }
        void setCloseCallback(const TcpCloseCallback& cb) { closeCallback_ = cb; }
        boost::asio::io_context& getNextIoContext();

    private:
        void handleNewConnection(TcpConnectionPtr&);
        void handleCloseConnection(TcpConnectionPtr&);
        void handleWriteComplete(TcpConnectionPtr&, const TcpDataPacketPtr&);
        void handleMessage(TcpConnectionPtr&, TcpUniqDataPacketPtr&&);

    private:
        boost::asio::io_context     mainIO_;
        TcpAcceptor                 acceptor_;
        std::vector<boost::asio::io_context>    workIOs_;
        size_t                      next_;
        std::vector<std::unique_ptr<clusnet::base::Thread>>     wthreads_;
        std::vector<std::unique_ptr<clusnet::base::Thread>>     mthreads_;
        std::unordered_set<TcpConnectionPtr>                    conns_;
        std::vector<Work>        workers_;

        TcpNewConnectionCallback   newConnCallback_;
        TcpCloseCallback           closeCallback_;
        TcpWriteCompleteCallback   writeCallback_;
        TcpMessageCallback         messageCallback_; 
};
}
}


#endif
